package org.mbds.wolf.android.idgo800;

import java.util.Arrays;

import android.content.Context;

import com.gemalto.idgo800.IDGoConstants;
import com.gemalto.idgo800.IDGoErrors;
import com.gemalto.idgo800.IDGoMain;
import com.gemalto.idgo800.pki.MdAPI;

/**
 * 
 * @author alesas
 * This class provides a simplified interface with IDGo800 SDK
 * for IDPrime MD microSD 8840
 *
 */
public class IDGo800MDHelper implements Runnable
{
	/*
	 *  Internal parameter to check the SDK was initialized
	 */
	private boolean isInitialized = false;
	/*
	 *  Android context
	 */
	private Context m_context = null;
	/*
	 *  MD service
	 */
	private MdAPI m_mdService = new MdAPI();
	/*
	 * MD session ID
	 */
	private int m_mdSessionId = -1;
	/*
	 *  Application signature provided by Gemalto
	 */
	private byte[] m_appSignature = null;
	/*
	 *  List of params for run process 
	 */
	private final Object[] params = new Object[10]; //Only 6 currently used
	/*
	 *  Last returned error
	 */
	private int lastError;
	/*
	 *  Action to be processed
	 */
	private Integer action;
	/*
	 *  Timeout for the run process
	 */
	public final static long TIMEOUT = 3000; //3 seconds maximum wait
	
	
	/**
	 * @Constructor IDGo800MDHelper
	 * @param context
	 * @param deviceType see IDGoConstants:
	 * - IDGoConstants.DEVICE_TYPE_AUTO_SELECT
	 * - IDGoConstants.DEVICE_TYPE_BLUETOOTH_LE
	 * - IDGoConstants.DEVICE_TYPE_NFC
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_DEFAULT
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_ESE
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_SD
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_UICC
	 * - IDGoConstants.DEVICE_TYPE_SOFT
	 * - IDGoConstants.DEVICE_TYPE_USB
	 * @param cardType see IDGoConstants:
	 * - IDGoConstants.CARD_TYPE_AUTO_SELECT
	 * - IDGoConstants.CARD_TYPE_MD
	 * - IDGoConstants.CARD_TYPE_NET
	 * - IDGoConstants.CARD_TYPE_PIV
	 * - IDGoConstants.CARD_TYPE_SOFT
	 * @param appSignature
	 */
	public IDGo800MDHelper(Context context, int deviceType, int cardType, byte[] appSignature) 
	{
		this.m_context = context;
		this.m_appSignature = appSignature;
		IDGoMain.initialize(context);
		m_mdSessionId = initMdServices(deviceType, cardType, m_context.getPackageName(), m_appSignature);
	}

	/**
	 * @Constructor IDGo800MDHelper
	 * @param context
	 * @param deviceType see IDGoConstants:
	 * - IDGoConstants.DEVICE_TYPE_AUTO_SELECT
	 * - IDGoConstants.DEVICE_TYPE_BLUETOOTH_LE
	 * - IDGoConstants.DEVICE_TYPE_NFC
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_DEFAULT
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_ESE
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_SD
	 * - IDGoConstants.DEVICE_TYPE_OMAPI_UICC
	 * - IDGoConstants.DEVICE_TYPE_SOFT
	 * - IDGoConstants.DEVICE_TYPE_USB
	 * @param appSignature
	 */
	public IDGo800MDHelper(Context context, int deviceType, byte[] appSignature) 
	{
		this(context, deviceType, IDGoConstants.CARD_TYPE_AUTO_SELECT, appSignature);
	}

	/**
	 * @Constructor IDGo800MDHelper
	 * @param context
	 * @param appSignature
	 */
	public IDGo800MDHelper(Context context, byte[] appSignature) 
	{
		this(context, IDGoConstants.DEVICE_TYPE_AUTO_SELECT, appSignature);
	}
	
	/**
	 * initMdService
	 * @param deviceType
	 * @param cardType
	 * @param packageName
	 * @param appSignature
	 * @return
	 */
	private int initMdServices(int deviceType, int cardType, String packageName, byte[] appSignature)
	{
		if (IDGoMain.isInitialized())
		{
			m_mdSessionId = m_mdService.MD_Init(deviceType, cardType, packageName, appSignature);
			isInitialized = m_mdSessionId>=0;
		    if (!isInitialized)
		    {
		    	//TODO: Manage error
		    }
		}
	    else
	    {
	    	//TODO: Manage error
	    }
	    return m_mdSessionId;
	}
	
	/**
	 * isInitialized
	 * @return
	 */
	public boolean isInitialized()
	{
		return isInitialized;
	}

	/**
	 * finalize
	 */
	@Override
	public void finalize() throws Throwable 
	{
		if (IDGoMain.isInitialized())
		{
			try
			{
				// Deauthenticate all users
				m_mdService.MD_DeauthenticateEx(m_mdSessionId, (byte)Constants.ROLE_ALL_ROLES);
				// Disconnect Mini Driver service
				m_mdService.MD_Finalize(m_mdSessionId);
			} catch (Exception e)
			{
				//Check if an exception is thrown
			}
			try
			{
				// Release IDGo800 API
				IDGoMain.release();
			} catch (Exception e)
			{
				//Check if an exception is thrown
			}
		}
		super.finalize();
	}
	
	/**
	 * runThread: Run the thread and wait end notification
	 * @return int last error
	 */
	private Object[] runThread() throws IDGo800Exception
	{
		lastError = IDGoErrors.GE_OK;
		// Run the request into a thread
		new Thread(this).start();

		// Wait the end of thread
		try 
		{
			synchronized (params) 
        	{             
				params.wait(TIMEOUT);         
        	} 			
	    } catch (InterruptedException e) 
		{
	    	lastError = Constants.ERR_TIMEOUT;
		} 
		if (lastError!=IDGoErrors.GE_OK)
		{
			throw new IDGo800Exception(lastError);
		}
		return params;
	}

	/**
	 * the params Object[] contains called function parameters:
	 * params[0] is the MD action to call parameter  
	 * 
	 */
	@Override
	public void run() {
		byte[] res;
		byte mode;
		byte role;
		byte[] pin;
        byte newRole;
        byte[] newPin;
        byte index;
        byte byte1;
        byte byte2;
        byte byte3;
        byte[] param1;
        byte[] param2;
        boolean bool;
        String str;
        String[] strarray;
        int intval;
        int[] intarray;
 		// Process action: call MD API
		switch (((Integer)params[0]).intValue())
		{
			case Constants.ACTION_AUTH_EX:
				mode = ((Byte)params[1]).byteValue();
				role = ((Byte)params[2]).byteValue();
				pin = (byte[])params[3];
				res = m_mdService.MD_AuthenticateEx(m_mdSessionId, mode, role, pin);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_AUTH_PIN:
				role = ((Byte)params[1]).byteValue();
				pin = (byte[])params[2];
				m_mdService.MD_AuthenticatePin(m_mdSessionId, role, pin);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_BEGIN_TRANSAC:
				m_mdService.MD_BeginTransaction(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_CHANGE_AUTHENTICATOR_EX:
				mode = ((Byte)params[1]).byteValue();
				role = ((Byte)params[2]).byteValue();
				pin = (byte[])params[3];
				newRole = ((Byte)params[4]).byteValue();
				newPin = (byte[])params[5];
				intval = ((Integer)params[6]).intValue();
				m_mdService.MD_ChangeAuthenticatorEx(m_mdSessionId, mode, role, pin, newRole, newPin, intval);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_CHANGE_REF_DATA:
				mode = ((Byte)params[1]).byteValue();
				role = ((Byte)params[2]).byteValue();
				pin = (byte[])params[3];
				newPin = (byte[])params[4];
				intval = ((Integer)params[5]).intValue();
				m_mdService.MD_ChangeReferenceData(m_mdSessionId, mode, role, pin, newPin, intval);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_CONSTRUCT_DH_AGREEMENT:
				index = ((Byte)params[1]).byteValue();
                param1 = (byte[])params[2];
                param2 = (byte[])params[3];
				res = m_mdService.MD_ConstructDHAgreement(m_mdSessionId, index, param1, param2);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_CREATE_CONTAINER:
				index = ((Byte)params[1]).byteValue();
				bool =  ((Boolean)params[2]).booleanValue();
                byte1 = ((Byte)params[3]).byteValue();
				intval = ((Integer)params[5]).intValue();
                param1 = (byte[])params[4];
                byte2 = m_mdService.MD_CreateContainer(m_mdSessionId, index, bool, byte1, intval, param1);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = byte2;
				break;
			case Constants.ACTION_CREATE_DIR:
				str = (String)params[1];
				param1 = (byte[])params[2];
				m_mdService.MD_CreateDirectory(m_mdSessionId, str, param1);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_CREATE_FILE:
				str = (String)params[1];
				param1 = (byte[])params[2];
				intval = ((Integer)params[3]).intValue();
				m_mdService.MD_CreateFile(m_mdSessionId, str, param1, intval);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_CREATE_FILE_EX:
				str = (String)params[1];
				param1 = (byte[])params[2];
				param2 = (byte[])params[3];
				m_mdService.MD_CreateFileEx(m_mdSessionId, str, param1, param2);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_DEAUTH:
                role = ((Byte)params[1]).byteValue();
                m_mdService.MD_Deauthenticate(m_mdSessionId, role);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_DEAUTH_EX:
                role = ((Byte)params[1]).byteValue();
                m_mdService.MD_DeauthenticateEx(m_mdSessionId, role);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_DELETE_CONTAINER:
                index = ((Byte)params[1]).byteValue();
                m_mdService.MD_DeleteContainer(m_mdSessionId, index);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_DELETE_DIR:
                str = (String)params[1];
                m_mdService.MD_DeleteDirectory(m_mdSessionId, str);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_DELETE_FILE:
                str = (String)params[1];
                m_mdService.MD_DeleteFile(m_mdSessionId, str);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_END_TRANSAC:
				m_mdService.MD_EndTransaction(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_EXTERNAL_AUTH:
                res = (byte[])params[1];
                m_mdService.MD_ExternalAuthenticate(m_mdSessionId, res);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_FLUSH_CARD_CACHE:
				m_mdService.MD_FlushCardCache(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_GENERIC_COMMAND:
				intval = ((Integer)params[1]).intValue();
                param1 = (byte[])params[2];
				res = m_mdService.MD_GenericCommand(m_mdSessionId, intval, param1);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_CARD_PROP:
				byte1 = ((Byte)params[1]).byteValue();
                byte2 = ((Byte)params[2]).byteValue();
				res = m_mdService.MD_GetCardProperty(m_mdSessionId, byte1, byte2);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_CARD_TYPE:
				intval = m_mdService.MD_GetCardType(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Integer.valueOf(intval);
				break;
			case Constants.ACTION_GET_CHALLENGE:
				res = m_mdService.MD_GetChallenge(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_CHALLENGE_EX:
				role = ((Byte)params[1]).byteValue();
				res = m_mdService.MD_GetChallengeEx(m_mdSessionId, role);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_CONTAINER:
				index = ((Byte)params[1]).byteValue();
				res = m_mdService.MD_GetContainer(m_mdSessionId, index);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_CONTAINER_PROP:
				index = ((Byte)params[1]).byteValue();
				byte1 = ((Byte)params[2]).byteValue();
				byte2 = ((Byte)params[3]).byteValue();
				res = m_mdService.MD_GetContainerProperty(m_mdSessionId, index, byte1, byte2);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_FILES:
				str = (String)params[1];
				strarray = m_mdService.MD_GetFiles(m_mdSessionId, str);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = strarray;
				break;
			case Constants.ACTION_GET_FILE_PROP:
				str = (String)params[1];
				res = m_mdService.MD_GetFileProperties(m_mdSessionId, str);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_IS_ADMIN_PERSONALIZED:
				bool = m_mdService.MD_IsAdminPersonalized(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Boolean.valueOf(bool);
				break;
			case Constants.ACTION_GET_IS_AUTHENTICATED:
				role = ((Byte)params[1]).byteValue();
				bool = m_mdService.MD_IsAuthenticated(m_mdSessionId, role);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Boolean.valueOf(bool);
				break;
			case Constants.ACTION_GET_IS_ECC:
				bool = m_mdService.MD_IsECC(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Boolean.valueOf(bool);
				break;
			case Constants.ACTION_GET_IS_USER_PERSONALIZED:
				bool = m_mdService.MD_IsUserPersonalized(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Boolean.valueOf(bool);
				break;
			case Constants.ACTION_GET_KEYS_AND_CERTIFICATES:
				res = m_mdService.MD_GetKeysAndCertificates(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_KEYS_AND_CERTIFICATES_EX:
				res = m_mdService.MD_GetKeysAndCertificatesEx(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_SERIAL_NUMBER:
				res = m_mdService.MD_GetSerialNumber(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_GET_TRIES_REMAINING:
				role = ((Byte)params[1]).byteValue();
				intval = m_mdService.MD_GetTriesRemaining(m_mdSessionId, role);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = Integer.valueOf(intval);
				break;
			case Constants.ACTION_GET_VERSION:
				str = m_mdService.MD_GetVersion(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = str;
				break;
			case Constants.ACTION_QUERY_CAPABILITIES:
				res = m_mdService.MD_QueryCapabilities(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_QUERY_FREE_SPACE:
				intarray = m_mdService.MD_QueryFreeSpace(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = intarray;
				break;
			case Constants.ACTION_QUERY_KEY_SIZES:
				intarray = m_mdService.MD_QueryKeySizes(m_mdSessionId);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = intarray;
				break;
			case Constants.ACTION_QUERY_KEY_SIZES_EX:
				byte1 = ((Byte)params[1]).byteValue();
				intarray = m_mdService.MD_QueryKeySizesEx(m_mdSessionId, byte1);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = intarray;
				break;
			case Constants.ACTION_READ_FILE:
				str = (String)params[1];
				intval = ((Integer)params[2]).intValue();
				res = m_mdService.MD_ReadFile(m_mdSessionId, str, intval);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_RSA_DECRYPT:
				index = ((Byte)params[1]).byteValue();
				byte1 = ((Byte)params[2]).byteValue();
				byte2 = ((Byte)params[3]).byteValue();
				byte3 = ((Byte)params[4]).byteValue();
				param1 = (byte[])params[4];
				res = m_mdService.MD_RsaDecrypt(m_mdSessionId, index, byte1, byte2, byte3, param1);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_SET_CARD_PROP:
				byte1 = ((Byte)params[1]).byteValue();
				param1 = (byte[])params[2];
				byte2 = ((Byte)params[3]).byteValue();
				m_mdService.MD_SetCardProperty(m_mdSessionId, byte1, param1, byte2);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_SET_CONTAINER_PROP:
				index = ((Byte)params[1]).byteValue();
				byte1 = ((Byte)params[2]).byteValue();
				param1 = (byte[])params[3];
				byte2 = ((Byte)params[4]).byteValue();
				m_mdService.MD_SetContainerProperty(m_mdSessionId, index, byte1, param1, byte2);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			case Constants.ACTION_SIGN_DATA:
				index = ((Byte)params[1]).byteValue();
				byte1 = ((Byte)params[2]).byteValue(); 
				byte2 = ((Byte)params[3]).byteValue();
				byte3 = ((Byte)params[4]).byteValue(); 
				param1 = (byte[])params[5];
				res = m_mdService.MD_SignData(m_mdSessionId, index, byte1, byte2, byte3, param1);
				Arrays.fill(params, 0, params.length-1, null);
				params[0] = res;
				break;
			case Constants.ACTION_WRITE_FILE:
				str = (String)params[1];
				param1 = (byte[])params[2];
				m_mdService.MD_WriteFile(m_mdSessionId, str, param1);
				Arrays.fill(params, 0, params.length-1, null);
				break;
			default:
				lastError = Constants.ERR_ACTION_NOT_FOUND;
				notifyUnlock(false);
		        return;
		}
		notifyUnlock(true);
    }
	
	/**
	 * getLastError
	 * @return error number int
	 */
	public int getLastError()
	{
		return m_mdService.MD_GetLastError();
	}
	
	/**
	 * notifyUnlock
	 */
	private void notifyUnlock(boolean updateLastError)
	{
		if (updateLastError) 
		{
			lastError = getLastError();
		}
		// Notify unlock waiting processes
        synchronized (params) {             
        	params.notify();         
        } 		
	}
	
	
	/**
	 * MD_AuthenticateUser
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser() throws IDGo800Exception
	{
		byte role = Constants.ROLE_USER;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateUser3
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser3() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ROLE3;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateUser4
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser4() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ROLE4;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateUser5
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser5() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ROLE5;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateUser6
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser6() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ROLE6;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateUser7
	 * @throws IDGo800Exception
	 * Authenticate User with PIN entry request
	 */
	public void MD_AuthenticateUser7() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ROLE7;
		MD_AuthenticatePin(role, null);
	}

	/**
	 * MD_AuthenticateAdmin
	 * @throws IDGo800Exception
	 * Authenticate Admin with PIN entry request
	 */
	public void MD_AuthenticateAdmin() throws IDGo800Exception
	{
		byte role = Constants.ROLE_ADMIN;
		MD_AuthenticateRole(role);
	}
	
	/**
	 * MD_AuthenticateCardAdmin
	 * @throws IDGo800Exception
	 * Authenticate Card Admin with PIN entry request
	 */
	public void MD_AuthenticateCardAdmin() throws IDGo800Exception
	{
		byte role = Constants.ROLE_CARD_ADMIN;
		MD_AuthenticateRole(role);
	}
	
	/**
	 * MD_AuthenticateRole
	 * @param role
	 * @return
	 * @throws IDGo800Exception
	 * Authenticate a role with PIN entry request
	 */
	private byte[] MD_AuthenticateRole(byte role) throws IDGo800Exception
	{
		return MD_AuthenticateEx((byte)0x00, role, null);
	}

	/**
	 * MD_AuthenticateEx
	 * @param mode
	 * @param role
	 * @param pin
	 * @return byte[]: The session PIN value in case of session PIN generation, else null
	 * @throws IDGo800Exception
	 * Authenticates a role according to the specified authentication mode
	 */
	private byte[] MD_AuthenticateEx(byte mode, byte role, byte[] pin) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_AUTH_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(mode);
		params[2] = Byte.valueOf(role);
		params[3] = pin;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_AuthenticatePin
	 * @param role
	 * @param pin
	 * @throws IDGo800Exception
	 * Authenticates the User PIN role or an extended PIN role (role #3 to #7)
	 */
	private void MD_AuthenticatePin(byte role, byte[] pin) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_AUTH_PIN);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(role);
		params[2] = pin;
		runThread();
	}

//	/**
//	 * MD_BeginTransaction
//	 * This method is deprecated since v3.0.0 due to its library architecture, and does nothing.
//	 * @return boolean
//	 * @throws IDGo800Exception
//	 * Deprecated
//	 */
//	@Deprecated 
//	public boolean MD_BeginTransaction() throws IDGo800Exception
//	{
//		action = Integer.valueOf(Constants.ACTION_BEGIN_TRANSAC);
//		Arrays.fill(params, 0, params.length-1, null);
//		params[0] = action;
//		runThread();
//		return Boolean.valueOf((Boolean)params[0]);
//	}

	/**
	 * MD_ChangeAuthenticatorEx
	 * Changes or unblocks the value of a PIN or Admin role.
	 * @param mode
	 * @param authRole
	 * @param authPin
	 * @param newRole
	 * @param newPin
	 * @param maxTries
	 * @throws IDGo800Exception
	 */
	public void MD_ChangeAuthenticatorEx(byte mode, byte authRole, byte[] authPin, byte newRole, byte[] newPin, int maxTries)  throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CHANGE_AUTHENTICATOR_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(mode);
		params[2] = Byte.valueOf(authRole);
		params[3] = authPin;
		params[4] = Byte.valueOf(newRole);
		params[5] = newPin;
		params[6] = Integer.valueOf(maxTries);
		runThread();
	}

	/**
	 * MD_ChangeReferenceData
	 * @param mode
	 * @param role
	 * @param authPin
	 * @param newPin
	 * @param maxTries
	 * @throws IDGo800Exception
	 * Changes or unblocks the value of a PIN or Admin role.
	 */
	public void MD_ChangeReferenceData(byte mode, byte role, byte[] authPin, byte[] newPin, int maxTries) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CHANGE_REF_DATA);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(mode);
		params[2] = Byte.valueOf(role);
		params[3] = authPin;
		params[4] = newPin;
		params[5] = Integer.valueOf(maxTries);
		runThread();
	}

	/**
	 * MD_ConstructDHAgreement
	 * Constructs a DH agreement (for key derivation) with a key container of the PKI Service.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the User role if it is not already authenticated.
	 * Only the IDPrime MD card supports this command.
	 * @param ctrIndex: 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int)
	 * @param dataQx: The Qx parameter.
	 * @param dataQy: The QY parameter.
	 * @return byte[]: The generated ECC DH agreement
	 * @throws IDGo800Exception
	 */
	public byte[] MD_ConstructDHAgreement(byte ctrIndex, byte[] dataQx, byte[] dataQy) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CONSTRUCT_DH_AGREEMENT);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex);
		params[2] = dataQx;
		params[3] = dataQy;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_CreateContainer
	 * Imports or generates (OBKG) a key-pair into a key container of the PKI Service.
	 * @param ctrIndex:  0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int). If 0xFF, the PKI Service chooses the first available container
	 * @param keyImport: false for OBKG, true for key import.
	 * @param keySpec: The key type as defined in IDGoConstants. The following key types are supported for this operation: IDGoConstants.KEYSPEC_KEYEXCHANGE, IDGoConstants.KEYSPEC_SIGNATURE, IDGoConstants.KEYSPEC_ECDSA_P256, IDGoConstants.KEYSPEC_ECDSA_P384, IDGoConstants.KEYSPEC_ECDSA_P521, IDGoConstants.KEYSPEC_ECDHE_P256, IDGoConstants.KEYSPEC_ECDHE_P384, IDGoConstants.KEYSPEC_ECDHE_P521.
	 * @param keySize: The key size in bits.
	 * @param keyValue: The key blob that contains the key to import, null for OBKG.  
	 * The keyValue parameter must be formatted as follows for a RSA key-pair:
	 * keyValue = Prime P || Prime Q || Inverse Q || DP || DQ || Private Exponent D || Modulus || Public Exponent E
	 * Where:
	 * Prime P length = Key_Size_Bytes / 2 bytes
	 * Prime Q length = Key_Size_Bytes / 2 bytes
	 * Inverse Q length = Key_Size_Bytes / 2 bytes
	 * DP length = Key_Size_Bytes / 2 bytes
	 * DQ length = Key_Size_Bytes / 2 bytes
	 * Private Exponent D length = Key_Size_Bytes bytes
	 * Modulus length = Key_Size_Bytes bytes
	 * Public Exponent E length = 4 bytes
	 * The keyValue parameter must be formatted as follows for an ECC key-pair:
	 * keyValue = Key Type || Key Size (in bytes) || X || Y || D
	 * Where:
	 * Key Type length = 4 bytes
	 * Key Size length = 4 bytes
	 * X length = Key Size bytes
	 * Y length = Key Size bytes
	 * D length = Key Size bytes
	 * The supported ECC Key Types are as follows:
	 * ECDSA 256: 0x32534345
	 * ECDSA 384: 0x34534345
	 * ECDSA 521: 0x36534345
	 * ECDH 256: 0x324B4345
	 * ECDH 384: 0x344B4345
	 * ECDH 521: 0x364B4345     
	 * @return The index of used container if method was called with ctrIndex = 0xFF.
	 * @throws IDGo800Exception
	 */
	public byte MD_CreateContainer(byte ctrIndex, boolean keyImport, byte keySpec, int keySize, byte[] keyValue) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CREATE_CONTAINER);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex);
		params[2] = Boolean.valueOf(keyImport);
		params[3] = Byte.valueOf(keySpec);
		params[4] = Integer.valueOf(keySize);
		params[5] = keyValue;
		runThread();
		return Byte.valueOf((Byte)params[0]);
	}

	/**
	 * MD_CreateDirectory: Creates a directory in the PKI Service file system.
	 * @param path: The name of the directory to create. Maximum length is 8 characters.
	 * @param acls: Access conditions of the directory.
	 * The acls parameter is a 3- byte array formatted as follows:
	 * acls[0]: Admin AC.
	 * acls[1]: User AC.
	 * acls[2]: Everyone AC.
	 * Each AC is a bit mask of the following rights:
	 * Right_Write = IDGoConstants.RIGHT_WRITE
	 * Right_Read = IDGoConstants.RIGHT_READ 
	 * @throws IDGo800Exception
	 */
	public void MD_CreateDirectory(String path, byte[] acls) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CREATE_DIR);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		params[2] = acls;
		runThread();
	}

	/**
	 * MD_CreateFile Creates an empty file in the PKI Service file system.
	 * @param path The full path name of the file to create. Maximum length of short file name is 8 characters.
	 * @param acls: Access conditions of the file.
     * The acls parameter is a 3- byte array formatted as follows:
 	 * acls[0]: Admin AC.
 	 * acls[1]: User AC.
 	 * acls[2]: Everyone AC.
 	 * Each AC is a bit mask of the following rights:
 	 * Right_Execute = IDGoConstants.RIGHT_EXECUTE (RFU)
 	 * Right_Write = IDGoConstants.RIGHT_WRITE
 	 * Right_Read = IDGoConstants.RIGHT_READ 
	 * @param initialSize Initial size of the file in bytes. File will be initialized with initialSize bytes set to 0x00.
	 * @throws IDGo800Exception
	 */
	public void MD_CreateFile(String path, byte[] acls, int initialSize) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CREATE_FILE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		params[2] = acls;
		params[3] = Integer.valueOf(initialSize);
		runThread();
	}

	/**
	 * MD_CreateFileEx Creates a file with data value in the PKI Service file system.
	 * @param path The full path name of the file to create. Maximum length of short file name is 8 characters.
	 * @param acls: Access conditions of the file.
     * The acls parameter is a 3- byte array formatted as follows:
 	 * acls[0]: Admin AC.
 	 * acls[1]: User AC.
 	 * acls[2]: Everyone AC.
 	 * Each AC is a bit mask of the following rights:
 	 * Right_Execute = IDGoConstants.RIGHT_EXECUTE (RFU)
 	 * Right_Write = IDGoConstants.RIGHT_WRITE
 	 * Right_Read = IDGoConstants.RIGHT_READ 
	 * @param data Initial data value to put in the file.
	 * @throws IDGo800Exception
	 */
	public void MD_CreateFileEx(String path, byte[] acls, byte[] data) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_CREATE_FILE_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		params[2] = acls;
		params[3] = data;
		runThread();
	}

	/**
	 * MD_Deauthenticate Deauthenticates any role.
	 * @param role The PIN identifier to deauthenticate as defined in IDGoConstants. 
	 * The following PIN identifiers are supported for this operation: 
	 * - IDGoConstants.ROLE_USER, 
	 * - IDGoConstants.ROLE_ADMIN, 
	 * - IDGoConstants.ROLE_3, 
	 * - IDGoConstants.ROLE_4, 
	 * - IDGoConstants.ROLE_5, 
	 * - IDGoConstants.ROLE_6, 
	 * - IDGoConstants.ROLE_7.
	 * @throws IDGo800Exception
	 */
	public void MD_Deauthenticate(byte role) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_DEAUTH);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(role);
		runThread();
	}

	/**
	 * MD_DeauthenticateEx Deauthenticates one or more roles.
	 * @param roles A bit mask of the role identifiers to deauthenticate as defined in IDGoConstants. 
	 * The following PIN identifiers are supported for this operation: 
	 * - IDGoConstants.ROLE_USER, 
	 * - IDGoConstants.ROLE_ADMIN, 
	 * - IDGoConstants.ROLE_3, 
	 * - IDGoConstants.ROLE_4, 
	 * - IDGoConstants.ROLE_5, 
	 * - IDGoConstants.ROLE_6, 
	 * - IDGoConstants.ROLE_7.
	 * @throws IDGo800Exception
	 */
	public void MD_DeauthenticateEx(byte roles) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_DEAUTH_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(roles);
		runThread();
	}

	/**
	 * MD_DeleteContainer Deletes a key-pair from a key container of the PKI Service.
	 * @param ctrIndex 0x00...0xN-1. 
	 * Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @throws IDGo800Exception
	 */
	public void MD_DeleteContainer(byte ctrIndex) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_DELETE_CONTAINER);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex);
		runThread();
	}

	/**
	 * MD_DeleteDirectory Deletes a directory from the PKI Service file system.
	 * @param path - The name of the directory to delete. Maximum length is 8 characters.
	 * @throws IDGo800Exception
	 */
	public void MD_DeleteDirectory(String path) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_DELETE_DIR);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		runThread();
	}

	/**
	 * MD_DeleteFile Deletes a file in the PKI Service file system.
	 * @param path - The full path name of the file to delete. Maximum length of short file name is 8 characters.
	 * @throws IDGo800Exception
	 */
	public void MD_DeleteFile(String path) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_DELETE_FILE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		runThread();
	}

//	/**
//	 * MD_EndTransaction: This method is deprecated since v3.0.0 due to its library architecture, and does nothing.
//	 * @return
//	 * @throws IDGo800Exception
//	 */
//	@Deprecated 
//	public boolean MD_EndTransaction() throws IDGo800Exception
//	{
//		action = Integer.valueOf(Constants.ACTION_END_TRANSAC);
//		Arrays.fill(params, 0, params.length-1, null);
//		params[0] = action;
//		runThread();
//		return Boolean.valueOf((Boolean)params[0]);
//	}

	/**
	 * MD_ExternalAuthenticate - Authenticates the Admin role with a response to a challenge previously returned by MD_GetChallenge(int) command.
	 * @param response - The response to the challenge = 3DES_CBC(challenge, Admin Key).
	 * @throws IDGo800Exception
	 */
	public void MD_ExternalAuthenticate(byte[] response) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_EXTERNAL_AUTH);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = response;
		runThread();
	}

	/**
	 * MD_FlushCardCache - Flushes the cache of currently connected card.
	 * @throws IDGo800Exception
	 */
	public void MD_FlushCardCache() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_FLUSH_CARD_CACHE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
	}

	/**
	 * MD_GenericCommand - Executes a generic command with MdAPI.
	 * @param cmdId - The identifier of the command to execute.
	 * @param data - Optional data for command execution.
	 * @return The result of command execution.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GenericCommand(int cmdId, byte[] data) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GENERIC_COMMAND);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Integer.valueOf(cmdId);
		params[2] = data;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetCardProperty Returns card property from the PKI Service.
	 * @param property - The property identifier to be returned as defined in IDGoConstants. 
	 * The following card property identifiers are supported for this operation: 
	 * - IDGoConstants.CP_CARD_FREE_SPACE, 
	 * - IDGoConstants.CP_CARD_CAPABILITIES, 
	 * - IDGoConstants.CP_CARD_KEYSIZES, 
	 * - IDGoConstants.CP_CARD_READ_ONLY, 
	 * - IDGoConstants.CP_CARD_CACHE_MODE, 
	 * - IDGoConstants.CP_CARD_GUID, 
	 * - IDGoConstants.CP_CARD_SERIAL_NO, 
	 * - IDGoConstants.CP_CARD_PIN_INFO, 
	 * - IDGoConstants.CP_CARD_LIST_PINS, 
	 * - IDGoConstants.CP_CARD_AUTHENTICATED_STATE, 
	 * - IDGoConstants.CP_CARD_PIN_STRENGTH_VERIFY, 
	 * - IDGoConstants.CP_CARD_PIN_POLICY, 
	 * - IDGoConstants.CP_CARD_IMPORT_ALLOWED, 
	 * - IDGoConstants.CP_CARD_CHANGE_PIN_FIRST, 
	 * - IDGoConstants.CP_CARD_VERSION_INFO.
	 * @param flags - Additional information depending on the property. See property value descriptions for details.
	 * @return The requested property value. 
	 * The format of the property value depends on the card property identifier as follows:
	 * - IDGoConstants.CP_CARD_FREE_SPACE: A byte array of 12 bytes containing the free space information.
	 * The returned blob is formatted as follows:
	 *    bytes[0...3] = Free memory size (in bytes) in the card (big-endian).
	 *    bytes[4...7] = Number of free containers in the card (big-endian).
	 *    bytes[8...11] = Maximum number of containers in the card (big-endian).
	 * - IDGoConstants.CP_CARD_CAPABILITIES: A byte array of 2 bytes formatted as follows:
	 *    byte[0]: Certificate compression
	 *    - 0x00: No
	 *    - 0x01: Yes
	 *    byte[1]: OBKG supported.
	 *    - 0x00: No
	 *    - 0x01: Yes
	 * - IDGoConstants.CP_CARD_KEYSIZES: A byte array of 16 bytes containing the key sizes information.
	 * The returned blob is formatted as follows:
	 *   bytes[0...3] = Minimum key length (big-endian).
	 *   bytes[4...7] = Default key length (big-endian).
	 *   bytes[8...11] = Maximum key length (big-endian).
	 *   bytes[12...15] = Increment key length (big-endian).
	 * - IDGoConstants.CP_CARD_READ_ONLY: A byte array of 1 byte that indicates if card is read-only or not.
	 * The returned blob is formatted as follows:
	 *   byte[0] = Read-only mode.
	 *   - 0x00 = Card is read/write (default).
	 *   - 0x01 = Card is read only.
	 * - IDGoConstants.CP_CARD_CACHE_MODE: A byte array of 1 byte that indicates the card cache mode.
	 * The returned blob is formatted as follows:
	 *   byte[0] = Cache mode.
	 *   - 0x01 = Global cache mode (default).
	 *   - 0x02 = Session cache mode.
	 *   - 0x03 = No cache mode.
	 * - IDGoConstants.CP_CARD_GUID: A byte array of 16 bytes that indicates the GUID (unique identifier) of the card. This is the same value as the 'cardid' file content.
	 * - IDGoConstants.CP_CARD_SERIAL_NO: A byte array of 12 bytes that indicates the Serial Number of the card.
	 * This is the unique chip serial number.
	 * - IDGoConstants.CP_CARD_PIN_INFO: A byte array of 12 bytes that indicates the PIN Information of a role.
	 * The flags parameter indicates the role identifier (User PIN, Admin Key, PIN#3, PIN#4, PIN#5, PIN#6 or PIN#7).
	 * The returned blob is formatted as follows:
	 *   byte[0] = PIN Type:
	 *   - IDGoConstants.PI_TYPE_REGULAR   -> Normal Alphanumeric PIN (default for User PIN and PIN#3 to PIN#7).
	 *   - IDGoConstants.PI_TYPE_EXTERNAL  -> External PIN (used for Biometrics or PIN pad).
	 *   - IDGoConstants.PI_TYPE_CHALLENGE -> Challenge/Response PIN (Default for Admin Key).
	 *   - IDGoConstants.PI_TYPE_EMPTY     -> No PIN (used for not protected keys).
	 *   byte[1] = PIN Purpose:
	 *   - IDGoConstants.PI_PURPOSE_AUTH            -> Authentication PIN.
	 *   - IDGoConstants.PI_PURPOSE_DIGITAL_SIGN    -> Digital Signature PIN.
	 *   - IDGoConstants.PI_PURPOSE_ENCRYPT         -> Encryption PIN.
	 *   - IDGoConstants.PI_PURPOSE_NON_REPUDIATION -> Non repudiation PIN.
	 *   - IDGoConstants.PI_PURPOSE_ADMIN           -> Admin PIN (default for Admin Key role).
	 *   - IDGoConstants.PI_PURPOSE_PRIMARY         -> Primary PIN (default for User PIN and PIN#3 to PIN#7 roles).
	 *   - IDGoConstants.PI_PURPOSE_UNBLOCK         -> Unblock PIN (PUK).
	 *   byte[2] = Bit-mask of roles identifier that allows unblock of the PIN. 
	 *   Default is Admin Keys for all PIN roles.
	 *   byte[3] = PIN Cache type, this is used by the Base CSP to manage PIN caching:
	 *   - IDGoConstants.PI_CACHE_NORMAL -> Normal cache, the Base CSP maintains cache per application (default).
	 *   - IDGoConstants.PI_CACHE_TIMED  -> Timed cache, the Base CSP flush its cache after a time period.
	 *   - IDGoConstants.PI_CACHE_NONE   -> No Cache, the Base CSP not maintains a cache.
	 *   byte[4...7] = Time period (in seconds) if PIN cache type is a timed cache (big-endian).
	 *   byte[8...11] = RFU.
	 * - IDGoConstants.CP_CARD_LIST_PINS: A byte array of 1 byte that indicates the roles supported by the card.
	 * The returned blob is formatted as follows:
	 *   byte[0] = Bit-mask of supported role identifiers. 0x7F in current version -> All roles.
	 * - IDGoConstants.CP_CARD_AUTHENTICATED_STATE: A byte array of 1 byte that indicates the roles currently authenticated by the card.
	 * The returned blob is formatted as follows:
	 *   byte[0] = Bit-mask of currently authenticated role identifiers.
	 * - IDGoConstants.CP_CARD_PIN_STRENGTH_VERIFY: A byte array of one byte that indicates the PIN strength of a role.
	 * The flags parameter indicates the role identifier (User PIN, PIN#3, PIN#4, PIN#5, PIN#6 or PIN#7).
	 * The returned blob is formatted as follows:
	 *   byte[0] = Bit-mask of PIN Strength of the role:
	 *   - 0x01 -> Supports plaintext mode verification.
	 *   - 0x02 -> Supports session PIN mode verification.
	 * - IDGoConstants.CP_CARD_PIN_POLICY: A byte array of 14 bytes that indicates the PIN Policy currently set on the card.
	 * The flags parameter indicates the role identifier (User PIN, PIN#3, PIN#4, PIN#5, PIN#6 or PIN#7).
	 * The returned blob is formatted as follows:
	 *   byte[0] = Maximum attempts before the PIN is blocked (1-255), default value is 5.
	 *   byte[1] = Minimum PIN length (4-255), default value is 4.
	 *   byte[2] = Maximum PIN length (4-255), default value is 255.
	 *   byte[3] = Authorized char set(s). This is a bits mask with the following char sets:
	 *   - 0x01 -> Numeric (0x30...0x39)
	 *   - 0x02 -> Alphabetic uppercase (0x41...0x5A)
	 *   - 0x04 -> Alphabetic lowercase (0x61...0x7A)
	 *   - 0x08 -> Non alphanumeric (0x20...0x2F + 0x3A...0x40 + 0x5B...0x60 +0x7B...0x7F)
	 *   - 0x10 -> Non ASCII (0x80...0xFF)
	 *   - 0x20 -> Alphabetic all (0x41...0x5A + 0x61...0x7A)
	 *   byte[4] = Number of different characters that can be repeated at least once (0-255), 255 if no limitation (default). This is also known as complexity rule 1.
	 *   byte[5] = Maximum number of times a character can appear (1-255), 255 if no limitation (default). This is also known as complexity rule 2.
	 *   byte[6] = Adjacent characters policy:
	 *   - 0x00 -> Repeated characters cannot be adjacent.
	 *   - 0x01 -> Repeated characters can be adjacent (default).
	 *   byte[7] = Number of previous PIN values a new PIN cannot match (0-10), 0 if no history (default).
	 *   byte[8] = Unblock policy:
	 *   - 0x00 -> PIN unblock is not permitted.
	 *   - 0x01 -> PIN unblock is permitted (default).
	 *   byte[9] = SSO policy:
	 *   - 0x00 -> PIN SSO is not activated (default).
	 *   - 0x01 -> PIN SSO is activated.
	 *   byte[10] = One character from each set usage policy:
	 *   - 0x00 -> Do not enforce PIN value composed with at least one character of each char set (default).
	 *   - 0x01 -> Enforce PIN value composed with at least one character of each char set.
	 *   byte[11] = Mandatory char set(s). This is a bits mask with the following char sets:
	 *   - 0x01 -> Numeric (0x30...0x39)
	 *   - 0x02 -> Alphabetic uppercase (0x41...0x5A)
	 *   - 0x04 -> Alphabetic lowercase (0x61...0x7A)
	 *   - 0x08 -> Non alphanumeric (0x20...0x2F + 0x3A...0x40 + 0x5B...0x60 +0x7B...0x7F)
	 *   - 0x10 -> Non ASCII (0x80...0xFF)
	 *   - 0x20 -> Alphabetic all (0x41...0x5A + 0x61...0x7A)
	 *   - 0x1F -> All chars (0x20...0xFF) (default)
	 *   byte[12] = Maximum length of character sequences e.g., 1,2,3,4 or a,b,c,d. 
	 *   For example, if set to 4, 1,2,3,4,a,5 is allowed, but 1,2,3,4,5,a is not allowed. Range is 1...255. Default is 255 (no limitation).
	 *   byte[13] = Maximum number of adjacent characters. Range is 1-255. Default is 255 (no limitation). 
	 *   This byte is ignored if adjacent characters policy is set to 00 (not allowed). This value cannot exceed the value of complexity rule 2.
	 * - IDGoConstants.CP_CARD_IMPORT_ALLOWED: A byte array of 1 byte that indicates if RSA key injection is permitted or not.
	 * The returned blob is formatted as follows:
	 *   byte[0] = Key injection allowed mode:
	 *   - 0x00 -> The card does not support RSA key injection.
	 *   - 0x01 -> The card supports RSA key injection (default).
	 * - IDGoConstants.CP_CARD_CHANGE_PIN_FIRST: A byte array of 1 byte that indicates the status of the  "Force PIN change at first use" property.
	 * The flags parameter indicates the role identifier (User PIN, PIN#3,  PIN#4, PIN#5, PIN#6 or PIN#7).
	 * The returned blob is formatted as follows:
	 *   byte[0] = Change PIN at first use mode:
	 *   - 0x00 -> Feature is not activated.
	 *   - 0x01 -> Feature is activated.
	 * - IDGoConstants.CP_CARD_VERSION_INFO: A byte array of 4 bytes that indicates the exact version number of the card application.
	 * The returned blob is formatted as follows:
	 *   byte[0...3] = 4-byte Version Number.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetCardProperty(byte property, byte flags) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CARD_PROP);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(property).byteValue();
		params[2] = Byte.valueOf(flags).byteValue();
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetCardType Returns the currently connected card type service.
	 * @return A card type as defined in IDGoConstants. 
	 * The following card types can be returned: 
	 * - IDGoConstants.CARD_TYPE_SOFT, 
	 * - IDGoConstants.CARD_TYPE_MD, 
	 * - IDGoConstants.CARD_TYPE_NET, 
	 * - IDGoConstants.CARD_TYPE_PIV.
	 */
	public int MD_GetCardType() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CARD_TYPE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return Integer.valueOf((Integer)params[0]);
	}

	/**
	 * MD_GetChallenge Generates a challenge for Admin authentication or PIN unblock.
	 * @return The generated challenge on 8 bytes.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetChallenge() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CHALLENGE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetChallengeEx Generates a challenge for a requested role.
	 * @param role  - The PIN identifier to get challenge for as defined in IDGoConstants. 
	 * The following roles are supported: 
	 * - IDGoConstants.ROLE_ADMIN
	 * @return The generated challenge on 8 bytes.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetChallengeEx(byte role) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CHALLENGE_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(role).byteValue();
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetContainer Returns the public key(s) from a key container of the PKI Service.
	 * Note: IDPrime PIV cards have 4 containers only, so the range of values is 0x00...0X03.
	 * @param ctrIndex 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @return A byte array blob that contains the signature and/or exchange public key(s) stored in the requested container.
	 * The returned key blob is formatted as follows:
	 *   Blob = [Signature Pub Key] || [Exchange Pub Key]
	 *   or
	 *   Blob = [Exchange Pub Key] || [Signature Pub Key]
	 * The order of the two keys in the blob depends on the configuration of the card.
	 * Signature Pub Key and Exchange Pub Key are optional depending on which key exists in the container and are sequences of TLV formatted as follows:
	 *   T_Key_Type = 0x03
	 *   L_Key_Type = 0x01
	 *   V_Key_Type = 0x01 for RSA Exchange, 
	 *     0x02 for RSA Signature, 
	 *     0x03 for ECDSA 256, 
	 *     0x04 for ECDSA 384, 
	 *     0x05 for ECDSA 521, 
	 *     0x06 for ECDH 256, 
	 *     0x07 for ECDH 384 and 
	 *     0x08 for ECDH 521.
	 *   T_Key_RSA_Pub_Exp = 0x01
	 *   L_Key_RSA_Pub_Exp = Public key Exponent size.
	 *   V_Key_RSA_Pub_Exp = Value of Public key Exponent on L_Key_RSA_Pub_Exp bytes.
	 *   T_Key_RSA_Modulus = 0x02
	 *   L_Key_RSA_Modulus = Key Size (in bytes) >> 4 (1 byte!)
	 *   V_Key_RSA_Modulus = Value of Public key Modulus on Key Size bytes.
	 *   T_Key_ECC_X = 0x04
	 *   L_Key_ECC_X = Key Size (in bytes).
	 *   V_Key_ECC_X = Value of X.
	 *   T_Key_ECC_Y = 0x05
	 *   L_Key_ECC_Y = Key Size (in bytes).
	 *   V_Key_ECC_Y = Value of Y.
	 * The 4-bit shift on L_Key_RSA_Modulus is to be able to pass the Modulus length on 1 byte for values 64 to 256 (512 bits to 2,048 bits).
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetContainer(byte ctrIndex) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CONTAINER);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex).byteValue();
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetContainerProperty Returns property of a key container in the PKI Service.
	 * @param ctrIndex 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @param property The property identifier to be returned as defined in IDGoConstants. 
	 * The following container property identifiers are supported for this operation: 
	 * - IDGoConstants.CCP_CONTAINER_INFO, 
	 * - IDGoConstants.CCP_PIN_IDENTIFIER, 
	 * - IDGoConstants.CCP_CONTAINER_TYPE.
	 * @param flags Additional information depending on the property (RFU).
	 * @return The requested property value. 
	 * The format of the container property value depends on the container property identifier as follows:
	 * - IDGoConstants.CCP_CONTAINER_INFO:
	 *   A key blob formatted as follows:
	 *      Blob = [Signature Pub Key] || [Exchange Pub Key]
	 *      or
	 *      Blob = [Exchange Pub Key] || [Signature Pub Key]
	 * The order of the two keys in the blob depends on the configuration of the card.
	 * Signature Pub Key and Exchange Pub Key are optional depending on which key exists in the container and are sequences of TLV formatted as follows:
	 *   T_Key_Type = 0x03
	 *   L_Key_Type = 0x01
	 *   V_Key_Type = 0x01 for RSA Exchange, 
	 *                0x02 for RSA Signature,
	 *                0x03 for ECDSA 256, 
	 *                0x04 for ECDSA 384, 
	 *                0x05 for ECDSA 521, 
	 *                0x06 for ECDH 256, 
	 *                0x07 for ECDH 384 and 
	 *                0x08 for ECDH 521.
	 *    T_Key_RSA_Pub_Exp = 0x01
	 *    L_Key_RSA_Pub_Exp = Public key Exponent size.
	 *    V_Key_RSA_Pub_Exp = Value of Public key Exponent on L_Key_RSA_Pub_Exp bytes.
	 *    T_Key_RSA_Modulus = 0x02
	 *    L_Key_RSA_Modulus = Key Size (in bytes) >> 4 (1 byte!)
	 *    V_Key_RSA_Modulus = Value of Public key Modulus on Key Size bytes.
	 *    T_Key_ECC_X = 0x04
	 *    L_Key_ECC_X = Key Size (in bytes).
	 *    V_Key_ECC_X = Value of X.
	 *    T_Key_ECC_Y = 0x05
	 *    L_Key_ECC_Y = Key Size (in bytes).
	 *    V_Key_ECC_Y = Value of Y.
	 * The 4-bit shift on L_Key_RSA_Modulus is to be able to pass the Modulus length on 1 byte for values 64 to 256 (512 bits to 2,048 bits).
	 * - IDGoConstants.CCP_PIN_IDENTIFIER: A byte array of one byte that indicates the role (User PIN or PIN#3 to PIN#7) that must be authenticated to use the keys in the container.
	 * - IDGoConstants.CCP_CONTAINER_TYPE: A byte array of two bytes that indicates if the keys in the container were imported or generated on board.
	 * The returned blob is formatted as follows:
	 *   blob[0] = 0x00 if signature key was imported, 
	 *             0x01 if it was OBKG.
	 *   blob[1] = 0x00 if exchange key was imported, 
	 *             0x01 if it was OBKG.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetContainerProperty(byte ctrIndex, byte property, byte flags) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_CONTAINER_PROP);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex).byteValue();
		params[2] = Byte.valueOf(property).byteValue();
		params[3] = Byte.valueOf(flags).byteValue();
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetFileProperties Returns properties of a file in the PKI Service file system.
	 * @param path The full path name of the file whose properties are to be returned. Maximum length of short file name is 8 characters.
	 * @return A 7-byte array with the file properties as follows:
	 *   bytes[0...2] = File acls.
	 *   bytes[3...6] = File size coded on 4 bytes (little-endian).
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetFileProperties(String path) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_FILE_PROP);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetFiles Returns files/sub-directories list from a directory in the PKI Service file system.
	 * @param path The path name of the directory to be listed. Maximum directory name length is 8 characters. 
	 *   If path = null; returns files from root directory. 
	 *   If path = "root"; returns sub-directories list from root directory.
	 * @return A string array with the files/sub-directories list from the directory.
	 * @throws IDGo800Exception
	 */
	public String[] MD_GetFiles(String path) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_FILES);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		runThread();
		return (String[])params[0];
	}

	/**
	 * MD_GetKeysAndCertificates Returns all the certificates and their associated key containers information from the PKI Service.
	 * @return An array blob formatted as follows:
	 *    Blob = Header || [Containers]*
	 *    Header is formatted as follows:
	 *    - header[0] = 0x00
	 *    - header[1] = 0x01
	 *    - header[2] = Number of containers.
	 *    Containers is a set of "Number of containers" TLV sequences (header[2]) formatted as follows:
	 *      //The Certificate associated with the container:
	 *      T_Cert = 0x01
	 *      L_Cert = Length of certificate value on 2 bytes (big endian).
	 *      V_Cert = Value of certificate on L_Cert bytes.
	 *      // The Key Container index associated with the certificate.
	 *      T_Key_Id = 0x02
	 *      L_Key_Id = 0x01
	 *      V_Key_Id = Container Index (always one byte).
	 *      // The Key Type
	 *      T_Key_Type = 0x03
	 *      L_Key_Type = 0x01
	 *      V_Key_Type = 0x01 for RSA Exchange, 
	 *                   0x02 for RSA Signature, 
	 *                   0x03 for ECDSA 256, 
	 *                   0x04 for ECDSA 384, 
	 *                   0x05 for ECDSA 521, 
	 *                   0x06 for ECDH 256, 
	 *                   0x07 for ECDH 384 and 
	 *                   0x08 for ECDH 521 (always one byte).
	 *       // The Key Length in bits.
	 *       T_Key_Len = 0x04
	 *       L_Key_Len = 0x02
	 *       V_Key_Len = Length of the key in bits on L_Key_Len bytes (big endian).  
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetKeysAndCertificates() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_KEYS_AND_CERTIFICATES);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetKeysAndCertificatesEx Returns all the certificates and their associated key containers information from the PKI Service.
	 * @return An array blob formatted as follows:
	 *    Blob = Header || [Containers]*
	 *    Header is formatted as follows:
	 *    - header[0] = 0x00
	 *    - header[1] = 0x01
	 *    - header[2] = Number of containers.
	 *    Containers is a set of "Number of containers" TLV sequences (header[2]) formatted as follows:
	 *      //The Certificate associated with the container:
	 *      T_Cert = 0x01
	 *      L_Cert = Length of certificate value on 2 bytes (big endian).
	 *      V_Cert = Value of certificate on L_Cert bytes.
	 *      // The Key Container index associated with the certificate.
	 *      T_Key_Id = 0x02
	 *      L_Key_Id = 0x01
	 *      V_Key_Id = Container Index (always one byte).
	 *      // The Key Type
	 *      T_Key_Type = 0x03
	 *      L_Key_Type = 0x01
	 *      V_Key_Type = 0x01 for RSA Exchange, 
	 *                   0x02 for RSA Signature, 
	 *                   0x03 for ECDSA 256, 
	 *                   0x04 for ECDSA 384, 
	 *                   0x05 for ECDSA 521, 
	 *                   0x06 for ECDH 256, 
	 *                   0x07 for ECDH 384 and 
	 *                   0x08 for ECDH 521 (always one byte).
	 *       // The Key Length in bits.
	 *       T_Key_Len = 0x04
	 *       L_Key_Len = 0x02
	 *       V_Key_Len = Length of the key in bits on L_Key_Len bytes (big endian).   
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetKeysAndCertificatesEx() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_KEYS_AND_CERTIFICATES_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetLastError Returns the execution status code of the last executed method.
	 * @return An error code value defined in IDGoErrors.
	 * @throws IDGo800Exception
	 */
	public int MD_GetLastError() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_LAST_ERROR);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return Integer.valueOf((Integer)params[0]);
	}

	/**
	 * MD_GetSerialNumber Gets the card serial number from the PKI Service.
	 * @return 16-byte array that contains the card serial number (same as cardid).
	 * @throws IDGo800Exception
	 */
	public byte[] MD_GetSerialNumber() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_SERIAL_NUMBER);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_GetTriesRemaining Returns the number of remaining tries for the requested role or PIN.
	 * @param role
	 * @return
	 * @throws IDGo800Exception
	 */
	public int MD_GetTriesRemaining(byte role) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_TRIES_REMAINING);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(role).byteValue();
		runThread();
		return Integer.valueOf((Integer)params[0]);
	}

	/**
	 * MD_GetVersion Gets the card application version from the PKI Service.
	 * @return A string that indicates the card application version.
	 * @throws IDGo800Exception
	 */
	public String MD_GetVersion() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_VERSION);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (String)params[0];
	}

	/**
	 * MD_IsAdminPersonalized Indicates if the Admin role has already been personalized.
	 * @return true if the Admin role has been personalized, else false.
	 * @throws IDGo800Exception
	 */
	public boolean MD_IsAdminPersonalized() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_IS_ADMIN_PERSONALIZED);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return Boolean.valueOf((Boolean)params[0]);
	}

	/**
	 * MD_IsAuthenticated Indicates if the requested role is authenticated or not.
	 * @param role The requested role identifier as defined in IDGoConstants. 
	 *  The following PIN identifiers are supported for this operation: 
	 *  - IDGoConstants.ROLE_USER, 
	 *  - IDGoConstants.ROLE_ADMIN, 
	 *  - IDGoConstants.ROLE_3, 
	 *  - IDGoConstants.ROLE_4, 
	 *  - IDGoConstants.ROLE_5, 
	 *  - IDGoConstants.ROLE_6, 
	 *  - IDGoConstants.ROLE_7.
	 * @return true if the requested role has been authenticated, else false.
	 * @throws IDGo800Exception
	 */
	public boolean MD_IsAuthenticated(byte role) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_IS_AUTHENTICATED);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(role).byteValue();
		runThread();
		return Boolean.valueOf((Boolean)params[0]);
	}

	/**
	 * MD_IsECC Indicates if the PKI Service supports ECC.
	 * @return true if the PKI Service supports ECC, false if the PKI Service does not support ECC.
	 * @throws IDGo800Exception
	 */
	public boolean MD_IsECC() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_IS_ECC);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return Boolean.valueOf((Boolean)params[0]);
	}

	/**
	 * MD_IsUserPersonalized Indicates if the User role has already been personalized.
	 * @return true if the User role has been personalized, else false.
	 * @throws IDGo800Exception
	 */
	public boolean MD_IsUserPersonalized() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_GET_IS_USER_PERSONALIZED);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return Boolean.valueOf((Boolean)params[0]);
	}

	/**
	 * MD_QueryCapabilities
	 * @return A 2-byte array formatted as follows:
	 *   byte[0]: Cert compression
	 *   - 0x00: No
	 *   - 0x01: Yes
	 *   byte[1]: OBKG supported.
	 *   - 0x00: No
	 *   - 0x01: Yes
	 * @throws IDGo800Exception
	 */
	public byte[] MD_QueryCapabilities() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_QUERY_CAPABILITIES);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_QueryFreeSpace Queries the card free space from the PKI Service.
	 * @return A 3-integer array formatted as follows:
	 *    int[0]: Number of used containers.
	 *    int[1]: Maximum number of containers.
	 *    int[2]: Free bytes memory.
	 * @throws IDGo800Exception
	 */
	public int[] MD_QueryFreeSpace() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_QUERY_FREE_SPACE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (int[])params[0];
	}

	/**
	 * MD_QueryKeySizes Asks the card for the supported RSA key sizes from the PKI Service.
	 * @return A 4-integer array formatted as follows:
	 *    int[0]: Minimum key size (bits).
	 *    int[1]: Maximum key size (bits).
	 *    int[2]: Key size increment (bits).
	 *    int[3]: Default key size.
	 * @throws IDGo800Exception
	 */
	public int[] MD_QueryKeySizes() throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_QUERY_KEY_SIZES);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
		return (int[])params[0];
	}

	/**
	 * MD_QueryKeySizesEx Asks the card for the supported key sizes for the specified key type from the PKI Service.
	 * @param keySpec - The key type as defined in IDGoConstants. 
	 * The following key types are supported for this operation: 
	 * - IDGoConstants.KEYSPEC_KEYEXCHANGE, 
	 * - IDGoConstants.KEYSPEC_SIGNATURE, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P256, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P384, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P521, 
	 * - IDGoConstants.KEYSPEC_ECDHE_P256, 
	 * - IDGoConstants.KEYSPEC_ECDHE_P384, 
	 * - IDGoConstants.KEYSPEC_ECDHE_P521.
	 * @return A 4-integer array formatted as follows:
	 *   int[0]: Minimum key size (bits).
	 *   int[1]: Maximum key size (bits).
	 *   int[2]: Key size increment (bits).
	 *   int[3]: Default key size.  
	 * @throws IDGo800Exception
	 */
	public int[] MD_QueryKeySizesEx(byte keySpec) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_QUERY_KEY_SIZES_EX);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(keySpec).byteValue();
		runThread();
		return (int[])params[0];
	}

	/**
	 * MD_ReadFile Reads a file in the PKI Service file system.
	 * @param path  - The full path name of the file to read from. Maximum length of short file name is 8 characters.
	 * @param maxBytesToRead - RFU. The full content of file is always read.
	 * @return The data read from the file.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_ReadFile(String path, int maxBytesToRead) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_READ_FILE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = path;
		params[2] = Integer.valueOf(maxBytesToRead).byteValue();
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_RsaDecrypt Deciphers data with a key container of the PKI Service.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the User role if it is not already authenticated.
	 * The available Padding types depends on the type of card, as follows: IDPrime MD: PKCS#1 and OAEP, IDPrime .NET: None and PKCS#1, IDPrime PIV: None and PKCS#1.
	 * @param ctrIndex - 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @param keySpecThe key type as defined in IDGoConstants. The following key types are supported for this operation: IDGoConstants.KEYSPEC_KEYEXCHANGE.
	 * @param paddingType - The padding type as defined in IDGoConstants. 
	 * The following padding types are supported for this operation: 
	 * - IDGoConstants.PADDING_NONE, 
	 * - IDGoConstants.PADDING_PKCS1, 
	 * - IDGoConstants.PADDING_OAEP.
	 * @param algo - The algorithm as defined in IDGoConstants. 
	 * It must be IDGoConstants.ALGO_NONE if padding is NONE or PKCS#1. 
	 * The following algorithms are supported for this operation with OAEP padding: 
	 * - IDGoConstants.ALGO_SHA_1, 
	 * - IDGoConstants.ALGO_SHA_256, 
	 * - IDGoConstants.ALGO_SHA_384, 
	 * - IDGoConstants.ALGO_SHA_512.
	 * @param encryptedData - The data to decipher, length must be equal to key length.
	 * @return The deciphered data (padding removed).
	 * @throws IDGo800Exception
	 */
	public byte[] MD_RsaDecrypt(byte ctrIndex, byte keySpec, byte paddingType, byte algo, byte[] encryptedData) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_RSA_DECRYPT);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex).byteValue();
		params[2] = Byte.valueOf(keySpec).byteValue();
		params[3] = Byte.valueOf(paddingType).byteValue();
		params[4] = Byte.valueOf(algo).byteValue();
		params[5] = encryptedData;
		runThread();
		return (byte[])params[0];
	}

	//
	/**
	 * MD_SetCardProperty Sets a card property in the PKI Service.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the Admin role if it is not already authenticated.
	 * The IDPrime PIV card is read-only and so does not support this function at all. In this case MD_GetLastError() returns IDGoErrors.GE_NOT_SUPPORTED.
	 * @param property - The property identifier to be set as defined in IDGoConstants. 
	 * The following card property identifiers are supported for this operation: 
	 * - IDGoConstants.CP_CARD_READ_ONLY, 
	 * - IDGoConstants.CP_CARD_CACHE_MODE, 
	 * - IDGoConstants.CP_CARD_GUID, 
	 * - IDGoConstants.CP_CARD_PIN_INFO, 
	 * - IDGoConstants.CP_CARD_PIN_POLICY, 
	 * - IDGoConstants.CP_CARD_CHANGE_PIN_FIRST.
	 * @param data - The card property value to set as a byte array blob. 
	 *  See MD_GetCardProperty(int, byte, byte) for details about card property value format.
	 * @param flags - Additional information depending on the property.
	 * @throws IDGo800Exception
	 */
	public void MD_SetCardProperty(byte property, byte[] data, byte flags) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_SET_CARD_PROP);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(property).byteValue();
		params[2] = data;
		params[3] = Byte.valueOf(flags).byteValue();
		runThread();
	}

	/**
	 * MD_SetContainerProperty Sets a property of a key container in the PKI Service.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the Admin role if it is not already authenticated.
	 * The IDPrime PIV card is read-only and so does not support this function at all. In this case MD_GetLastError() returns IDGoErrors.GE_NOT_SUPPORTED.
	 * @param ctrIndex - 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @param property - The property identifier to be set as defined in IDGoConstants. The following container property identifiers are supported for this operation: IDGoConstants.CCP_PIN_IDENTIFIER.
	 * @param data - The container property value to set as a byte array blob. See MD_GetContainerProperty(int, byte, byte, byte) for details about container property value format.
	 * @param flags - Additional information depending on the property (RFU).
	 * @throws IDGo800Exception
	 */
	public void MD_SetContainerProperty(byte ctrIndex, byte property, byte[] data, byte flags) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_SET_CONTAINER_PROP);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex).byteValue();
		params[2] = Byte.valueOf(property).byteValue();
		params[3] = data;
		params[4] = Byte.valueOf(flags).byteValue();
		runThread();
	}

	/**
	 * MD_SignData Signs data with a key container of the PKI Service.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the Admin role if it is not already authenticated.
	 * The IDPrime PIV card is read-only and so does not support this function at all. In this case MD_GetLastError() returns IDGoErrors.GE_NOT_SUPPORTED.
	 * @param ctrIndex - 0x00...0xN-1. Container index where N is the maximum number of containers as returned by int [1] of MD_QueryFreeSpace(int).
	 * @param keySpec - The key type as defined in IDGoConstants. 
	 * The following key types are supported for this operation: 
	 * - IDGoConstants.KEYSPEC_SIGNATURE, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P256, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P384, 
	 * - IDGoConstants.KEYSPEC_ECDSA_P521.
	 * @param paddingType - The padding type as defined in IDGoConstants. 
	 * The following padding types are supported for this operation: 
	 * - IDGoConstants.PADDING_PKCS1, 
	 * - IDGoConstants.PADDING_PSS.
	 * @param algo - The algorithm as defined in IDGoConstants. 
	 * The following algorithms are supported for this operation: 
	 * - IDGoConstants.ALGO_NONE, 
	 * - IDGoConstants.ALGO_MD2, 
	 * - IDGoConstants.ALGO_MD4, 
	 * - IDGoConstants.ALGO_MD5, 
	 * - IDGoConstants.ALGO_SHA_1, 
	 * - IDGoConstants.ALGO_SHA_256, 
	 * - IDGoConstants.ALGO_SHA_384, 
	 * - IDGoConstants.ALGO_SHA_512.
	 * @param dataToSign - The data to sign, length according to hash algorithm used.
	 * @return The data signature.
	 * @throws IDGo800Exception
	 */
	public byte[] MD_SignData(byte ctrIndex, byte keySpec, byte paddingType, byte algo, byte[] dataToSign) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_SIGN_DATA);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		params[1] = Byte.valueOf(ctrIndex).byteValue();
		params[2] = Byte.valueOf(keySpec).byteValue();
		params[3] = Byte.valueOf(paddingType).byteValue();
		params[4] = Byte.valueOf(algo).byteValue();
		params[5] = dataToSign;
		runThread();
		return (byte[])params[0];
	}

	/**
	 * MD_WriteFile Writes a data value in a file in the PKI Service file system.
	 * Notes:
	 * The PKI Service automatically displays a pop-up to authenticate the Admin role if it is not already authenticated.
	 * The IDPrime PIV card is read-only and so does not support this function at all. In this case MD_GetLastError() returns IDGoErrors.GE_NOT_SUPPORTED.
	 * @param path - The full path name of the file to write to. Maximum length of short file name is 8 characters.
	 * @param data - Data value to write in the file.
	 * @throws IDGo800Exception
	 */
	public void MD_WriteFile(String path, byte[] data) throws IDGo800Exception
	{
		action = Integer.valueOf(Constants.ACTION_WRITE_FILE);
		Arrays.fill(params, 0, params.length-1, null);
		params[0] = action;
		runThread();
	}
}
